#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author:zhengxin
@file: 01_abnormal_error.py
@time: 2024/12/4  11:41
# @describe: 异常和错误
"""


""" 1. 异常处理 -- try/except """
while True:
    try:
        x = int(input("请输入一个数字: "))
        break
    except ValueError:
        print("您输入的不是数字，请再次尝试输入！")



"""
一个except子句可以同时处理多个异常，这些异常将被放在一个括号里成为一个元组，例如:
    except (RuntimeError, TypeError, NameError):
        pass
        
最后一个except子句可以忽略异常的名称，它将被当作通配符使用。你可以使用这种方法打印一个错误信息，然后再次把异常抛出。
"""
import sys

try:
    f = open("myfile.txt")
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS ERROR: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise




""" 
 2.异常处理--  try/except...else
    try/except 语句还有一个可选的 else 子句，如果使用这个子句，那么必须放在所有的 except 子句之后。
    else 子句将在 try 子句没有发生任何异常的时候执行。
"""
a = 3
try:
    if a == 1:
        print(a)
except ValueError:
    print("类型错误")
else:
    print("111111")





""" 
 3.异常处理-- try-finally 语句

    try-finally 语句无论是否发生异常都将执行最后的代码。
"""
def runoob():
    pass
try:
    runoob()
except AssertionError as error:
    print(error)
else:
    try:
        with open('file.log') as file:
            read_data = file.read()
    except FileNotFoundError as fnf_error:
        print(fnf_error)
finally:
    print('这句话，无论异常是否发生都会执行。')





""" 
 4.抛出异常-- Python 使用 raise 语句抛出一个指定的异常。

    raise语法格式如下：
        raise [Exception [, args [, traceback]]]
"""

# x = 10
# if x > 5:
#     raise Exception("x 不能大于 5. x的值为：{}".format(x))



""" 
 raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类（也就是 Exception 的子类）。
    如果你只想知道这是否抛出了一个异常，并不想去处理它，那么一个简单的 raise 语句就可以再次把它抛出。
 """

# try:
#     raise NameError('HiThere')
# except NameError:
#     print('An exception flew by!')
#     raise




""" 
 5.抛出异常-- 用户自定义异常
    你可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类，可以直接继承，或者间接继承，例如:
"""
class MyError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

try:
    raise MyError(2*2)
except MyError as e:
    print('My exception occurred, value:', e.value)



""" 
 抛出异常-- 用户自定义异常
    当创建一个模块有可能抛出多种不同的异常时，一种通常的做法是为这个包建立一个基础异常类，然后基于这个基础类为不同的错误情况创建不同的子类:
"""
class Error(Exception):
    """ 此模块中异常的基类 """
    pass

class InputError(Error):
    """
    输入错误引发异常。
    属性：
        expression--发生错误的输入表达式
        message--错误的解释
    """
    def __init__(self, expression, message):
        self.expression = expression
        self.message = message


class TransitionError(Error):
    """
    当操作尝试状态转换而不是状态转换时引发允许。
    属性:
        previous -- 转换开始时的状态
        next -- 尝试新状态
        message -- 解释为什么不允许特定的转换
    """
    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message



"""
 预定义的清理行为
    关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法:
 """
try:
    with open("myfile.txt") as f:
        for line in f:
            print(line, end="")
except FileNotFoundError:
    print("文件不存在")
